package com.gzsxy.esjy.service.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gzsxy.esjy.bus.message.InnerProtocol;
import com.gzsxy.esjy.bus.message.MessageFactory;
import com.gzsxy.esjy.common.base.exception.impl.CustomAssert;
import com.gzsxy.esjy.common.base.result.ResultCodeEnum;
import com.gzsxy.esjy.common.base.util.FileUtils;
import com.gzsxy.esjy.feign.Product.ProductFeignService;
import com.gzsxy.esjy.feign.cart.CartFeignService;
import com.gzsxy.esjy.redis.user.ISystemUser;
import com.gzsxy.esjy.service.base.DictionaryConstants;
import com.gzsxy.esjy.service.base.dto.request.ApiOrderRequest;
import com.gzsxy.esjy.service.base.dto.response.*;
import com.gzsxy.esjy.service.base.util.Page;
import com.gzsxy.esjy.service.order.dao.OrderMapper;
import com.gzsxy.esjy.service.order.entity.Order;
import com.gzsxy.esjy.service.order.entity.OrderProduct;
import com.gzsxy.esjy.service.order.entity.vo.OrderQueryVo;
import com.gzsxy.esjy.service.order.service.OrderProductService;
import com.gzsxy.esjy.service.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.*;

/**
 * @author xiaolong
 * @version 1.0
 * @description: 订单
 * @date 2022/2/17 17:46
 */
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private ISystemUser iSystemUser;

//    @Qualifier("productFeignService")
    @Autowired
    private ProductFeignService productFeignService;

//    @Qualifier("cartFeignService")
    @Autowired
    private CartFeignService cartFeignService;

    @Autowired
    private OrderProductService orderProductService;

    @Autowired
    private ThreadPoolTaskExecutor threadPool;

    @Autowired
    private MessageFactory messageFactory;


    private String jsonString = null;

    private  static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");




    /**
     * @description: 初始化
     * @param
     * @return
     */
    @PostConstruct
    public void init() throws IOException {
        initDefault();

    }

    private void initDefault() throws IOException {
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        //优先读取外面的
        getResources(resolver,"classpath:json/order.json");
        getResources(resolver,"file:json/order.json");
    }


    private void getResources(ResourcePatternResolver resourceLoader,String path) throws IOException {
        Resource[] resources = resourceLoader.getResources(path);
        for (Resource resource : resources) {
            if (this.jsonString !=null){
                return;
            }
            String jsonString = FileUtils.readFile(resource.getInputStream());
            if (StringUtils.isNotBlank(jsonString)){
                this.jsonString = jsonString;
            }
        }
    }






    /**
     * @description: 分页查询订单
     * @param
     * @return
     */
    @Override
    public  IPage<OrderRsp> getPageVo(Page<?> page, OrderQueryVo orderQueryVo) {

        //分页查询订单
        IPage<OrderRsp> pageVo = baseMapper.getPageVo(page, orderQueryVo);
        List<OrderRsp> records = pageVo.getRecords();
        //是操控多个属性的原子性的并发类。
        AtomicReference<List<OrderRsp>> orderList = new AtomicReference<>();
        //计数器
        CountDownLatch latch = new CountDownLatch(records.size());
        try {
            threadPool.execute(()->{
                //TODO 会有问题（出现超时现象，做成并行）
                //设置收货地址转map对象,再通过遍历商品列表通过远程调用商品微服务拿到商品的图片信息

                    orderList.set(records.stream().map(record -> {
                            record.getMatedataRsp().setMap(JSON.parseObject(record.getMatedataRsp().getContent()));
                            return record;
                        }).map(record -> {
                            record.getProductList().stream().map(productRsp -> {
                                productRsp.setProductPic((List<ProductPicRsp>) productFeignService.getPicByProductId(productRsp.getId()).getData());
                                return productRsp;
                            }).collect(toList());
                             //计数器减一
                            latch.countDown();
                            return record;
                        }).collect(toList())
                );
            });
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            //计数器归零后再执行以下任务，不然在多并发下，有些线程提前完成后就关闭连接池，后续的线程就无法执行
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //判断当前用户是否为系统管理员（默认查询全部订单）
            Boolean isAdmin = (Boolean) iSystemUser.get("isAdmin", true);
            if (!isAdmin){
                String userId = (String) iSystemUser.get("id", "");
                if (StringUtils.isNotEmpty(userId)){
                    //TODO 后台根据登录用户获取当前用户订单 (同一个订单下商品都属于同一个商家，所有可以直接获取列表第一个的商品用户id)
                    orderList.set(orderList.get().stream().filter(obj -> obj.getProductList().get(0).getUserId().equals(userId)).collect(toList()));
                }
            }
            //关闭连接池(不能关闭，否则下一次调用连接为空会报错)
//            threadPool.shutdown();
            return pageVo.setRecords(orderList.get());
        }
    }


    /**
     * @description: 改变订单状态 
     * @param 
     * @return 
     */
    @Override
    public void eidtStatus(String orderId, Integer status) {
        Order order = baseMapper.selectById(orderId);
        //该订单不存在
        CustomAssert.notTrue(ObjectUtils.isNotEmpty(order), ResultCodeEnum.ORDER_NOT_EXIST_ERROR.getMessage());
        //锁同一个订单，同一时间只能一个线程修改状态
        synchronized (orderId.intern()) {
            order.setStatus(status);
            baseMapper.updateById(order);
        }
    }


    /**
     * @description: 删除订单
     * @param
     * @return
     */
    @Override
    public void deleteOrder(String id) {
        Order order = baseMapper.selectById(id);
        //该订单不存在
        CustomAssert.notTrue(ObjectUtils.isNotEmpty(order), ResultCodeEnum.ORDER_NOT_EXIST_ERROR.getMessage());
        baseMapper.deleteById(id);
    }


    /**
     * @description: 添加订单
     * @param
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<String>  addOrder(ApiOrderRequest apiOrderRequest) {
        //TODO 1.查询当前用户的购物车商品
//        DefaultResponse response = cartFeignService.getCartByUserId(apiOrderRequest.getUserId());
//        List<CartRsp> cartList = JSON.parseArray(JSON.toJSONString(response.getData()), CartRsp.class);

        //TODO  2.库存为0 或者 购物车里的产品数量大于库存数量
        CustomAssert.notTrue(!apiOrderRequest.getCartList().stream().anyMatch(cartRsp -> cartRsp.getProductRsp().getNumber() == 0),ResultCodeEnum.PRODUCT_NUMBER_ERROR.getMessage());
        CustomAssert.notTrue(!apiOrderRequest.getCartList().stream().anyMatch(cartRsp -> cartRsp.getNumber()>cartRsp.getProductRsp().getNumber()),ResultCodeEnum.PRODUCT_NUMBER_ERROR.getMessage());

        List<String> list = new ArrayList<>();
        //TODO 判断商品是否属于同一个用户，不同用户的商品要分开订单
        //根据不同商家对购物车商品进行分组
        Map<String, List<CartRsp>> groupByUserId = apiOrderRequest.getCartList().stream().collect(groupingBy(object -> object.getProductRsp().getUserId()));
        groupByUserId.forEach((k, v) -> {

            List<OrderProduct> orderProductList = new LinkedList<>();
            //总价
            double sumPrice = 0;
            //TODO 3.创建订单
            for (CartRsp cartRsp : v) {
                //总价
                sumPrice +=(cartRsp.getNumber() * cartRsp.getProductRsp().getPrice());

                int number = cartRsp.getProductRsp().getNumber() - cartRsp.getNumber();
                //TODO 5.更新商品库存
                productFeignService.editNumber(cartRsp.getProductId(),number);

                OrderProduct orderProduct = new OrderProduct();
                orderProduct.setProductId(cartRsp.getProductId());
                orderProduct.setNumber(cartRsp.getNumber());
                orderProductList.add(orderProduct);
            }
            Order order = new Order();
            DateFormat format=new SimpleDateFormat("yyyyMMdd");
            String uuid = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 6);
            String orderCode = "H" + format.format(new Date())+uuid;
            list.add(orderCode);
            order.setOrderCode(orderCode);
            //如果为在线支付0
            if (apiOrderRequest.getPaytype() ==0){
                order.setPaytype(apiOrderRequest.getPaytype());
                //待发货
                order.setStatus(DictionaryConstants.NUMBER_1);
                order.setPaytype2(apiOrderRequest.getPaytype2());
                //如果为货到付款1(只能本校区支持线下支付)
            } else {
                order.setPaytype(apiOrderRequest.getPaytype());
                //待支付
                order.setStatus(DictionaryConstants.NUMBER_1);
            }
            //设置用户id
            order.setUserId(apiOrderRequest.getUserId());
            order.setSumPrice(sumPrice);
            //收货地址id
            order.setResourceId(apiOrderRequest.getResourceId());
            orderMapper.insert(order);
            //TODO 订单商品入库
            List<OrderProduct> orderProducts = orderProductList.stream().map(orderProduct -> orderProduct.setOrderId(order.getId())).collect(toList());
            orderProductService.saveBatch(orderProducts);
            OrderCountRsp orderCountRsp = new OrderCountRsp();
            orderCountRsp.setUserId(k);
            orderCountRsp.setSalesNum(sumPrice);
            //发送统计管理服务消息，统计今日当前商家订单数加一
            messageFactory.send("service-statistical",new InnerProtocol().body(orderCountRsp).cmd(DictionaryConstants.ORDER_NUM));
        });
        //TODO 6.删除购物车
        cartFeignService.deleteByUserId(apiOrderRequest.getUserId());

        return list;
    }


    /**
     * @description: 统计订单各个状态数量
     * @param
     * @return
     */
    @Override
    public OrderCountRsp getStatusCount() {
        //判断当前用户是否为系统管理员（默认查询管理员所拥有的）
        String userId = null;
        Boolean isAdmin = (Boolean) iSystemUser.get("isAdmin", true);
        if (!isAdmin){
            userId = (String) iSystemUser.get("id", "");
        }
        OrderCountRsp orders = baseMapper.getStatusCount(userId);
        return orders;
    }

    /**
     * @description:   根据前台用户id获取订单列表
     * @param
     * @param page
     * @return
     */
    @Override
    public IPage<OrderRsp> getOrderByUserId(Page<?> page, OrderQueryVo orderQueryVo) {
        IPage<OrderRsp> pageVo = this.getPageVo(page, orderQueryVo);
        return pageVo;
    }


    /**
     * @description: 订单数统计
     * @param
     * @return
     */

    @Override
    public List<OrderCountRsp> getOrderStatistical(String day) {
        List<OrderCountRsp> list = orderMapper.getOrderStatistical(day);
        return list;
    }

    public static void main(String[] args) {
        System.out.println(DATE_FORMAT.format(new Date()));
    }
}
